package com.depth.viewer.utils
{
	import com.depth.viewer.utils.date.StringConvertDate;
	
	import flash.display.DisplayObject;
	import flash.events.MouseEvent;
	import flash.external.ExternalInterface;
	import flash.geom.Point;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	
	import mx.core.FlexGlobals;
	import mx.core.UITextFormat;
	import mx.formatters.DateFormatter;
	import mx.utils.ObjectUtil;
	
	import org.as3commons.lang.ObjectUtils;
	
	
	public class Util
	{
		
		public function Util()
		{
			
		}
		/**
		 *完全克隆对象 
		 * @param source
		 * @return 
		 * 
		 */		
		public static function clone(source:Object):* {
			/*var array : ByteArray = new ByteArray();
			array.writeObject(source);
			array.position = 0;
			return array.readObject();*/
			var obj:Object = CloneUtils.baseClone(source);
			return obj;
			//return CloneUtils.baseClone(source);
		}
		
		/**
		 * 将objFrom中的公共属性CPOY到objTo中,如果objFrom中的属性未定义值则不Cpoy此属性
		 * @param objTo
		 * @param objFrom
		 * 
		 */		
		public static function copyProperty(objTo:Object, objFrom:Object):void
		{
			if (objTo == null || objFrom == null)
				return;
			
			var claInfo:Object=ObjectUtil.getClassInfo(objTo);
			var props:Array=claInfo["properties"];
			for each (var q:QName in props)
			{
				try
				{
					if (objFrom.hasOwnProperty(q.localName))
					{
						if(objFrom[q.localName] is Number){
							if(!isNaN(objFrom[q.localName])){
								objTo[q.localName]=objFrom[q.localName];
							}
						}else{
							if (objFrom[q.localName] && !(objTo[q.localName] is Function))
							{
								objTo[q.localName]=objFrom[q.localName];
							}
						}
					}
				}
				catch (err:Error)
				{
				}
			}
		}
		
		public static function copyProperty1(objTo:Object, objFrom:Object,fitlerFields:Array = null):void
		{
			if (objTo == null || objFrom == null)
				return;
			
			var claInfo:Object=ObjectUtil.getClassInfo(objFrom);
			var props:Array=claInfo["properties"];
			for each (var q:QName in props)
			{
				try
				{
					if(!contains(fitlerFields,q.localName))
						objTo[q.localName]=objFrom[q.localName];
				}
				catch (err:Error)
				{
				}
			}
		}
		
		public static function getObjectAttributes(obj:Object,allowNullValue:Boolean = true):Array
		{
			var attributes:Array=[];
			var claInfo:Object=ObjectUtil.getClassInfo(obj);
			var props:Array=claInfo["properties"];
			
			if(obj is Dictionary){
				for each (var proName:String in props)
				{
					try
					{
						if (obj[proName] && !(obj[proName] is Function))
						{
							attributes.push(proName);
						}
					}
					catch (err:Error)
					{
						throw new Error("获取属性出错!");
					}
				}
			}else{
				for each (var q:QName in props)
				{
					try
					{
						if (allowNullValue && !(obj[q.localName] is Function))
						{
							attributes.push(q.localName);
						}else if (!allowNullValue && obj[q.localName] && !(obj[q.localName] is Function))
						{
							attributes.push(q.localName);
						}
					}
					catch (err:Error)
					{
						throw new Error("获取属性出错!");
					}
				}
			}
			return attributes;
		}
		
		/**
		 * Copy all properties of a source object to a destination object.
		 * Modifies the passed in destination object.
		 *
		 * @param destination The object that will be modified
		 * @param source The object with properties to be set on the destination
		 *
		 * @return The destination object
		 */
		public static function extend(destination:Object, source:Object):Object
		{
			for (var property:String in source)
			{
				destination[property]=source[property];
			}
			return destination;
		}
		
		/**
		 * Remove an item of an array
		 *
		 * @param array the array containing items
		 * @param item item to remove
		 *
		 * @return the new array
		 */
		public static function removeItem(array:Array, item:Object):Array
		{
			for (var i:int=0; i < array.length; i++)
			{
				if (array[i] == item)
				{
					array.splice(i, 1);
				}
			}
			return array;
		}
		public static function addItemAt(array:Array, item:Object, index:int):void
		{
			if (index > array.length)
				array.push(item);
			var tempArr:Array=[];
			for (var i=index; i < array.length; i++)
			{
				tempArr.push(array.pop());
			}
			array[index]=item;
			for (var k=tempArr.length - 1; k >= 0; k--)
			{
				array.push(tempArr[k]);
			}
			
		}
		
		/**
		 * Get the index of an object in an array
		 *
		 * @param array array containning items
		 * @param obj Item that we find index
		 *
		 * @return index of the item
		 */
		public static function indexOf(array:Array, obj:Object):int
		{
			for (var i:int=0; i < array.length; i++)
			{
				if (array[i] == obj)
					return i;
			}
			return -1;
		}
		
		/**
		 * Normalise scale
		 *
		 * @param scale
		 *
		 * @return return a normalized scale value, in 1 / X format
		 */
		public static function normalizeScale(scale:Number):Number
		{
			var normScale:Number=(scale > 1.0) ? (1.0 / scale) : scale;
			return normScale;
		}
		
		/**
		 * Store all the keys of the Object in uppercase
		 *
		 * @param object
		 *
		 * @return a new Object with all the same keys but uppercased
		 */
		public static function upperCaseObject(object:Object):Object
		{
			var uObject:Object=new Object();
			for (var key:String in object)
			{
				uObject[key.toUpperCase()]=object[key];
			}
			return uObject;
		}
		
		/**
		 * Get parameter
		 *
		 * @param params
		 *
		 * @return A concatenation of the properties of an object in http parameter notation
		 */
		public static function getParameterString(params:Object):String
		{
			var paramsArray:Array=new Array();
			
			for (var key:String in params)
			{
				var value:Object=params[key];
				if ((value != null) && (typeof value != 'function'))
				{
					var encodedValue:Object;
					if (typeof value == 'object' && value.constructor == Array)
					{
						/* value is an array; encode items and separate with "," */
						var encodedItemArray:Array=new Array();
						for (var itemIndex:int=0; itemIndex < value.length; itemIndex++)
						{
							encodedItemArray.push(encodeURIComponent(value[itemIndex]));
						}
						encodedValue=encodedItemArray.join(",");
					}
					else
					{
						/* value is a string; simply encode */
						encodedValue=encodeURIComponent(value.toString());
					}
					paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
				}
			}
			
			return paramsArray.join("&");
		}
		
		/**
		 * Get Ags
		 *
		 * @param url
		 *
		 * @return An object of key/value pairs from the query string
		 */
		public static function getArgs(url:String=null):Object
		{
			if (url == null)
			{
				url="";
			}
			var query:String=(url.indexOf('?') != -1) ? url.substring(url.indexOf('?') + 1) : '';
			
			var args:Object=new Object();
			var pairs:Array=query.split(/[&;]/);
			for (var i:int=0; i < pairs.length; ++i)
			{
				var keyValue:Array=pairs[i].split(/=/);
				if (keyValue.length == 2)
				{
					args[decodeURIComponent(keyValue[0])]=decodeURIComponent(keyValue[1]);
				}
			}
			return args;
		}
		
		public static function pagePosition(forElement:Object):Array
		{
			
			var element:Object=forElement;
			var globalPoint:Point=element.localToGlobal(new Point(0, 0));
			
			return [globalPoint.x, globalPoint.y];
		}
		
		public static function mouseLeft(evt:MouseEvent, can:DisplayObject):Boolean
		{
			var target:Object=evt.currentTarget
			
			while (target != can && target != null)
			{
				target=target.parent;
			}
			
			return (target != can);
		}
		
		/**
		 * Convert decimal degrees number into sexagecimal degrees string.
		 *
		 * @param dec decimal degrees.
		 * @param locals the axis direction (N, S) or (E, W). If undefined, null or empty, the leading
		 *               minus will prefix the decimal degrees string.
		 * @param numDigits number of figures in tenth of second.
		 *
		 * @return the sexagecimal value whose syntax conforms with dmsToDeg() function.
		 *
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9
		 * @author didier.richard@ign.fr
		 */
		public static function degToDMS(dec:Number, locals:Array=null, numDigits:Number=1):String
		{
			var positive_degrees:Number=Math.abs(dec);
			var degrees:Number=Math.round(positive_degrees + 0.5) - 1;
			var decimal_part:Number=60 * (positive_degrees - degrees);
			var minutes:Number=Math.round(decimal_part + 0.5) - 1;
			decimal_part=60 * (decimal_part - minutes);
			var seconds:Number=Math.round(decimal_part + 0.5) - 1;
			if (isNaN(numDigits) || numDigits < 0)
			{
				numDigits=1;
			}
			var k:Number=Math.pow(10, numDigits);
			var remains:Number=k * (decimal_part - seconds);
			remains=Math.round(remains + 0.5) - 1;
			if (remains >= k)
			{
				seconds=seconds + 1;
				remains=0;
			}
			if (seconds == 60)
			{
				minutes=minutes + 1;
				seconds=0;
			}
			if (minutes == 60)
			{
				degrees=degrees + 1;
				minutes=0;
			}
			var dir:String="";
			if (locals && (locals is Array) && locals.length == 2)
			{
				dir=" " + (dec > 0 ? locals[0] : locals[1]);
			}
			else
			{
				if (dec < 0)
				{
					degrees=-1 * degrees;
				}
			}
			
			var s:String=StringUtils.sprintf("%4d° %02d' %02d", degrees, minutes, seconds) + (numDigits > 0 ? StringUtils.sprintf(".%0*d", numDigits, remains) : "") + "\"" + dir;
			return s;
		}
		
		/**
		 * Convert a string representation of a sexagecimal degrees into a numeric representation of
		 * decimal degrees.
		 *
		 * @param dms a sexagecimal value. The supported syntax is :
		 * <listing version="3.0">
		 *    \s?-?(\d{1,3})[.,°d]?\s?(\d{0,2})[']?\s?(\d{0,2})[.,]?(\d{0,})(?:["]|[']{2})?
		 *    |
		 *    \s?(\d{1,3})[.,°d]?\s?(\d{0,2})[']?\s?(\d{0,2})[.,]?(\d{0,})(?:["]|[']{2})?\s?([NSEW])?
		 * </listing>
		 *
		 * @return the decimal value or NaN if error occurs.
		 *
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9
		 * @author didier.richard@ign.fr
		 */
		public static function dmsToDeg(dms:String):Number
		{
			if (dms == null)
			{
				return NaN;
			}
			var neg:Number=dms.match(/(^\s?-)|(\s?[SW]\s?$)/) != null ? -1.0 : 1.0;
			dms=dms.replace(/(^\s?-)|(\s?[NSEW]\s?)$/, '');
			dms=dms.replace(/\s/g, '');
			var parts:Array=dms.match(/(\d{1,3})[.,°d]?(\d{0,2})[']?(\d{0,2})[.,]?(\d{0,})(?:["]|[']{2})?/);
			if (parts == null)
			{
				return NaN;
			}
			// parts:
			// 0 : degrees
			// 1 : degrees
			// 2 : minutes
			// 3 : seconds
			// 4 : fractions of seconds
			var d:Number=parseFloat(parts[1] ? parts[1] : "0.0");
			var m:Number=parseFloat(parts[2] ? parts[2] : "0.0");
			var s:Number=parseFloat(parts[3] ? parts[3] : "0.0");
			var r:Number=parseFloat(parts[4] ? ("0." + parts[4]) : "0.0");
			var dec:Number=(d + (m / 60.0) + (s / 3600.0) + (r / 3600.0)) * neg;
			return dec;
		}
		
		/**
		 * Return sqrt(x<sup>2</sup> +y<sup>2</sup>) without intermediate overflow or underflow.
		 * Special cases:<ul>
		 * <li>If either argument is infinite, then the result is positive infinity.</li>
		 * <li>If either argument is NaN and neither argument is infinite, then the result is NaN.</li>
		 * </ul>
		 * The computed result must be within 1 ulp of the exact result. If one parameter is held
		 * constant, the results must be semi-monotonic in the other parameter.
		 *
		 * @param x a value.
		 * @param y a value.
		 *
		 * @return sqrt(x<sup>2</sup> +y<sup>2</sup>) without intermediate overflow or underflow.
		 */
		public function hypot(x:Number, y:Number):Number
		{
			if (!isFinite(x) || !isFinite(y))
			{
				return Infinity;
			}
			if (isNaN(x) || isNaN(y))
			{
				return NaN;
			}
			x=Math.abs(x);
			y=Math.abs(y);
			var r:Number, q:Number;
			if (x > y)
			{
				r=y / x;
				q=x;
			}
			else if (y > 0.0)
			{
				r=x / y;
				q=y;
			}
			else
			{
				return 0.0;
			}
			if (r == Number.MIN_VALUE)
			{
				return q;
			}
			r*=r;
			if (r == Number.MIN_VALUE)
			{
				return q;
			}
			r=q * Math.sqrt(1.0 + r * r);
			return r;
		}
		
		public static function connect(toArray:Array, fromArray:Array):void
		{
			for each (var obj:Object in fromArray)
			{
				toArray.push(obj);
			}
		}
		public static function contains(arr:Array,item:Object):Boolean{
			if(!arr||arr.length==0||!item){return false;}
			for each(var o:Object in arr){
				if(o == item){
					return true;
				}
			}
			return false;
		}
		
		public static function getOffsetTime(date1:Date,date2:Date):Number{
			var offsetTime:Number = (date2.getTime() - date1.getTime())/ 1000;
			return offsetTime;
		}
		/**
		 *给指定的Date对象追加时间 
		 * @param date
		 * @param year
		 * @param month
		 * @param day
		 * @param hour
		 * @param minute
		 * @param second
		 * 
		 */		
		public static function appendTime(date:Date,year:Number = 0,month:Number = 0,day:Number = 0,hour:Number = 0,minute:Number = 0,second:Number = 0):void{
			
			var _year:Number = date.fullYear + year;
			var _month:Number = date.month + month;
			var _day:Number = date.date + day;
			var _hour:Number = date.hours + hour;
			var _minute:Number = date.minutes + minute;
			var _second:Number = date.seconds + second;
			
			if(_second > 60){
				_minute += Math.floor(_second/60);
				_second = _second%60;
			}
			if(_minute > 60){
				_hour += Math.floor(_minute/60);
				_minute = _minute%60;
			}
			if(_hour > 24){
				_day += Math.floor(_hour/24);
				_hour = _hour%24;
			}
			if(_day > getMonthDay(date.fullYear,date.month)){
				_month = Math.floor(_day/getMonthDay(date.fullYear,date.month));
				_day = _day%getMonthDay(date.fullYear,date.month);
			}
			if(_month > 12){
				_year += Math.floor(_month/12);
				_month = _month%12;
			}
			date.setFullYear(_year,_month,_day);
			date.setHours(_hour,_minute,_second);
		}
		/**
		 * 获取url参数
		 */
		public static function getParams():Object {  
			var params:Object = {};  
			var query:String = ExternalInterface.call("window.location.search.substring", 1);  
			if(query) {  
				var pairs:Array = query.split("&");  
				for(var i:uint=0; i < pairs.length; i++) {  
					var pos:int = pairs[i].indexOf("=");  
					if(pos != -1) {  
						var argname:String = pairs[i].substring(0, pos);  
						var value:String = pairs[i].substring(pos+1);  
						params[argname] = value;  
					}  
				}  
			}  
			return params;  
		} 
		/**
		 *获取一系列点的最小范围 
		 * @param points
		 * @return 
		 * 
		 */		
		public static function getLocusExtent(points:Array):Array
		{
			if(points == null || points.length == 0) return null;
			var xmin:Number = points[0][0];
			var ymin:Number = points[0][1];
			var xmax:Number = points[0][0];
			var ymax:Number = points[0][1];
			for(var i:int = 0; i < points.length; i++){
				if(points[i][0] > xmax){
					xmax = points[i][0]; 
				}
				if(points[i][0] < xmin){
					xmin = points[i][0]; 
				}
				if(points[i][1] > ymax){
					ymax = points[i][1]; 
				}
				if(points[i][1] < ymin){
					ymin = points[i][1]; 
				}
			}
			
			var extent:Array = [xmin,ymin,xmax,ymax];
			return extent;
		}
		/**
		 * 角度转弧度
		 * @return
		 */
		public static function radianToAngle(radian:Number):Number{
			return radian * 180 / Math.PI;
		}
		/**
		 * 获取地球上两点经纬度距离
		 * @param lng1
		 * @param lat1
		 * @param lng2
		 * @param lat2
		 * @return 单位 米
		 */
		public static function getDistance(lng1:Number, lat1:Number, lng2:Number, lat2:Number):Number {
			if( ( Math.abs( lat1 ) > 90  ) ||(  Math.abs( lat2 ) > 90 ) ||  ( Math.abs( lng1 ) > 180  ) || (  Math.abs( lng2 ) > 180 ) ) return -1;
			var radLat1:Number = rad(lat1);
			var radLat2:Number = rad(lat2);
			var a:Number = radLat1 - radLat2;
			var b:Number = rad(lng1) - rad(lng2);
			var s:Number = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) + Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
			s = s * 6378.137 ;// EARTH_RADIUS;
			s = s * 1000;
			return s;
		}
		public static function rad(d:Number):Number{
			return d * Math.PI / 180.0;
		}
		/**
		 *计算某年某月的总天数 
		 * @param year
		 * @param month
		 * @return 
		 * 
		 */		
		public static function  getMonthDay(year:int, month:int):int
		{
			return (month > 12 || month <= 0) ? 0 : (month == 2 ? ((year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true)) ? 29 : 28) : (30 + (month <= 7 ? month : month + 1) % 2));
		} 
		public static function parserDateFromString(str:String):Date{
			return StringConvertDate.convertToDate(str);
		}
		public static function getNewDateTimeString():String{
			var formatter:DateFormatter = new DateFormatter();
			formatter.formatString = "YYYY-MM-DD JJ:NN:SS";
			var date:Date = new Date();
			date.month--;
			return formatter.format(date);
		}
		public static function transformDateDisplayFromString(str:String):String{
			if(str==null||str.length<11){return "";}
			var result:String = "";
			result+=str.substring(8,10)+":";
			result+=str.substring(10,12)+":";
			result+=str.substring(12,14);
			return result;
		}
		/**
		 * 返回类型类型  **日**时**分
		 * */
		public static function transformDateDDHHMMFromString(str:String):String{
			if(str==null||str.length<11){return "";}
			var result:String = "";
			result+=str.substring(6,8)+"日";
			result+=str.substring(8,10)+"时";
			result+=str.substring(10,12)+"分";
			return result;
		}
		/**
		 * 返回类型类型  **时**分**秒 形式为**:**:**
		 * */
		public static function transToHHMMSSFromString(str:String):String{
			if(str==null||str.length<11){return "";}
			var result:String = "";
			result+=str.substring(8,10)+":";
			result+=str.substring(10,12)+":";
			result+=str.substring(12,14);
			return result;
		}
		/**
		 * 返回类型类型  **时**分**秒 形式为**:**:**
		 * */
		public static function transToDispaly(str:String):String{
			if(str==null||str.length<12){return "";}
			var result:String = "";
			result+=str.substring(0,4)+"-";
			result+=str.substring(4,6)+"-";
			result+=str.substring(6,8)+" ";
			result+=str.substring(8,10)+":";
			result+=str.substring(10,12);
			if(str.length>12){
				result+= ":"+str.substring(12,14);
			}
			return result;
		}
		public static function getNewDateString():String{
			var dateTimeString:String = getNewDateTimeString();
			return dateTimeString.substring(0,dateTimeString.indexOf(" "));
		}
		public static function getNewTimeString():String{
			var dateTimeString:String = getNewDateTimeString();
			return dateTimeString.substring(dateTimeString.indexOf(" "),dateTimeString.length - 1);
		}
		public static function getNewRoundTimeString():String{
			var timeString:String = getNewTimeString();
			var h:String = timeString.substr(0,timeString.indexOf(":"));
			return h + ":" + "00:00";
		}
		public static function millisecondToDateDisplay(msd:String):String{
			var str:String;
			var time:Number = parseFloat(msd) /1000;
			if (time&&time>0) {
				if (time >60 && time <60*60) {
					str = Math.floor(time/60) +"分钟"+  Math.floor(time%60) +"秒"; 
				}else if (time >=60*60 && time < 60*60*24) {
					str = Math.floor(time /3600) +"小时"+  Math.floor((time%3600)/60) + "分钟" +  Math.floor((time%3600)%60) + "秒";
				}else {
					str = time + "秒";
				}
			}else{
				str = "--";
			}
			return str;
		}
		/**
		 *测量字条串的实际占用长度，主要用于测量特定字体特写大小的中文字符串的实际战用长度。  
		 * 此应用可用于需要根据一段文字自动扩展宽度的情况下、
		 * @param text 字条串
		 * @param fontFamily 字体
		 * @param fontSize 字体大小 
		 * @return 字符串的实际测量长度
		 * 
		 */		
		public static function measureTextWidth(text:String,fontFamily:String,fontSize:int = 12):Number{
			var uiTextFormat:UITextFormat = new UITextFormat(FlexGlobals.topLevelApplication.systemManager);
			uiTextFormat.antiAliasType = "normal";
			
			uiTextFormat.gridFitType = "pixel";
			
			uiTextFormat.font = fontFamily;
			
			uiTextFormat.size = fontSize;
			
			return uiTextFormat.measureText(text).width;
		}
		
		/**
		 * 获取Data通过这个格式"2012年12月17日 08点50分02秒";
		 * */
		public static function getDateByChinaData(str:String):Date{
			str = str.replace(" ","");
			var yyyy:String = str.substr(0,4);
			var mm:String = str.substr(5,2);
			mm = Number(mm)-1 +'';
			var dd:String = str.substr(8,2);
			var hh:String = str.substr(11,2);
			var min:String = str.substr(14,2);
			var ss:String = str.substr(17,2);
			return new Date(yyyy,mm,dd,hh,min,ss);
		}
	}
}

